package com.puzzlebazar.client.puzzle.model;

import java.util.Iterator;
import java.util.Vector;



/**
 * @author beaudoin
 *
 * Class that contains all the updates to apply to the
 * user interface
 *
 */
public class MoveList extends MoveImpl {

	/**
	 * 
	 */
	private static final long serialVersionUID = 7037985267473726600L;

	protected Vector<Move> moves = new Vector<Move>();
	
	/**
	 * Only for serialization
	 */
	protected MoveList() {
		super();
	}
	
	public MoveList(long time) {
		super(time);
	}

	/**
	 * Adds a move to the list
	 * 
	 * @param move Move to add
	 */
	public void addMove(Move move) {
		moves.add(move);
	}

	/**
	 * Appends a list of move to the list
	 * 
	 * @param move List of moves to append
	 */
	public void append(Move move) {
		if( move instanceof MoveList )
			moves.addAll( ((MoveList)move).moves );
		else
			addMove( move );
	}
	
	@Override
	public Move apply(PuzzleModel model) throws Exception {
		MoveList moveList = new MoveList(time);
		return applyDirect(model, moveList);
	}


	@Override
	public Move unapply(PuzzleModel model) throws Exception {
		MoveList moveList = new MoveList(time);
		return applyReverse(model, moveList);
	}


	/**
	 * Apply all the moves in the move list and add them to the passed movelist
	 * 
	 * @param model The model to apply the moves to
	 * @param moveList The MoveList to add moves to
	 * @return The resulting move list
	 * @throws Exception
	 */
	protected Move applyDirect(PuzzleModel model, MoveList moveList) throws Exception {
		for (Iterator<Move> iterator = moves.iterator(); iterator.hasNext();) {
			Move move = iterator.next();
			moveList.append( move.apply(model) );
		}
		return moveList;
	}

	/**
	 * Apply all the moves in the move list in reverse order and add them to the passed movelist
	 * 
	 * @param model The model to apply the moves to
	 * @param moveList The MoveList to add moves to
	 * @return The resulting move list
	 * @throws Exception
	 */
	protected Move applyReverse(PuzzleModel model, MoveList moveList) throws Exception {
		for( int i=moves.size(); i != 0; i--) {
			Move move = moves.elementAt( i-1 );
			moveList.append( move.unapply(model) );
		}
		return moveList;
	}

	@Override
	public void accept(MoveVisitor visitor) throws Exception {
		visitor.visitMoveList(this);
	}
	
	/**
	 * Sent the visitor to all the children of this move list, in order
	 * 
	 * @param visitor The visitor to send
	 * @throws Exception
	 */
	public void visitChildren(MoveVisitor visitor) throws Exception  {
		for (Iterator<Move> iterator = moves.iterator(); iterator.hasNext();) {
			Move move = (Move)iterator.next();
			move.accept(visitor);
		}
	}

	@Override
	public Move simplify() {
		if( moves.size() == 1 )
			return moves.get(0);
		
		return this;
	}

}
